package nckd.wnqjt.tmc.tda.plugin.form;

import com.alibaba.fastjson.JSON;
import kd.bos.ai.util.JsonUtil;
import kd.bos.algo.DataSet;
import kd.bos.algo.JoinType;
import kd.bos.algo.Row;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.entity.LocaleString;
import kd.bos.entity.AppInfo;
import kd.bos.entity.AppMetadataCache;
import kd.bos.entity.qing.*;
import kd.bos.entity.report.ReportQueryParam;
import kd.bos.form.IFormView;
import kd.bos.form.IPageCache;
import kd.bos.form.ShowType;
import kd.bos.form.control.IQingAnalysis;
import kd.bos.form.plugin.AbstractFormPlugin;
import kd.bos.list.ListShowParameter;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.mvc.SessionManager;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.report.ReportShowParameter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @author zhujintao
 * @date 2024/11/05
 * @desc 资金总额按银行大类
 */
public class TotalfundsByBankQingDataProvider extends AbstractFormPlugin implements IQingDataProvider {
    private static Log log = LogFactory.getLog(TotalfundsByBankQingDataProvider.class);


    /**
     * 获取表头信息定义
     */
    @Override
    public QingMeta getMeta(String pageId) {
        String entityKey = "bei_bankbalance";
        QingMeta meta = new QingMeta();
        EntryEntity entity = new EntryEntity();
        entity.setKey(entityKey); //实体名(唯一标识)	是
        entity.setName(new LocaleString("余额查询")); //实体别名	是
        entity.setPkFieldName("id");//主键名称	是
        meta.addEntryEntity(entity);

        Field column = new Field();
        column.setEntity(entityKey);//字段所属实体key	否
        column.setKey("bankaccountnumber");// 字段名(唯一标识)	是
        column.setFieldType(QingFieldType.String.toNumber()); //数据类型	是
        column.setName(new LocaleString("账号")); //字段别名	是
        meta.addColumn(column);

        column = new Field();
        column.setEntity(entityKey);
        column.setKey("bankbankcatename");
        column.setFieldType(QingFieldType.String.toNumber());
        column.setName(new LocaleString("银行大行"));
        meta.addColumn(column);

        column = new Field();
        column.setEntity(entityKey);
        column.setKey("amount");
        column.setFieldType(QingFieldType.Number.toNumber());
        column.setName(new LocaleString("当前余额"));
        meta.addColumn(column);

        column = new Field();
        column.setEntity(entityKey);
        column.setKey("unrestrictedamt");
        column.setFieldType(QingFieldType.Number.toNumber());
        column.setName(new LocaleString("受限金额"));
        meta.addColumn(column);

        column = new Field();
        column.setEntity(entityKey);
        column.setKey("surplusamount");
        column.setFieldType(QingFieldType.Number.toNumber());
        column.setName(new LocaleString("定期存款金额"));
        meta.addColumn(column);

        column = new Field();
        column.setEntity(entityKey);
        column.setKey("nckd_depositbalance");
        column.setFieldType(QingFieldType.Number.toNumber());
        column.setName(new LocaleString("上存余额"));
        meta.addColumn(column);
        return meta;
    }

    /**
     * 获取轻分析数据
     *
     * @param startRow 起始行
     * @param limit    每页的数据量
     * @return 轻分析数据
     */
    @Override
    public QingData getData(String pageId, int startRow, int limit) {
        //拿过滤条件，进行取数
        String qFilter = getPageCache().get("qFilter");
        Map<String, Object> filterParam = null;
        if (qFilter != null) {
            //通过此方法拿到过滤参数
            filterParam = (Map) JSON.parseObject(qFilter, Map.class);
        }
        //实体账户当前余额+受限资金管理中银行账户是虚拟户受限金额+定期存款管理中定期账户是虚拟户的投资理财
        /**
         * ***************************************************************
         */
        Date startdate;
        Date enddate;
        if (filterParam != null && filterParam.get("nckd_querydate") != null) {
            String querydatestr = String.valueOf(filterParam.get("nckd_querydate"));
            Date parseDate = null;
            try {
                parseDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(querydatestr);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            LocalDate localDate = LocalDate.from(LocalDateTime.ofInstant(parseDate.toInstant(), ZoneId.systemDefault()).toLocalDate());
            startdate = Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
            LocalDateTime enddateTime = localDate.atTime(23, 59, 59);
            enddate = Date.from(enddateTime.atZone(ZoneId.systemDefault()).toInstant());
        } else {
            //获取当前日期起止日期
            startdate = Date.from(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
            LocalDateTime enddateTime = LocalDate.now().atTime(23, 59, 59);
            enddate = Date.from(enddateTime.atZone(ZoneId.systemDefault()).toInstant());
        }
        QFilter beiBankbalanceFilter = new QFilter("bizdate", QCP.large_equals, startdate).and("bizdate", QCP.less_equals, enddate);

        //子公司当前余额+母公司当前余额 排除结算中心
        QFilter finorgtype = new QFilter("number", QCP.equals, "FI-015");
        DynamicObject queryOne = QueryServiceHelper.queryOne("bd_finorgtype", "id", finorgtype.toArray());
        if (queryOne != null) {
            Object pkValue = queryOne.getLong("id");
            beiBankbalanceFilter.and(new QFilter("bank.finorgtype.id", QCP.not_equals, pkValue));
        }
        log.info("资金总额按银行大类余额查询条件 " + beiBankbalanceFilter.toString());
        String beiBankbalanceSelectField = "id,company.id companyid,company.number companynumber,company.name companyname" +
                ",accountbank.id accountbankid,accountbank.bankaccountnumber bankaccountnumber,bank.bank_cate.id bankbankcateid,bank.bank_cate.number bankbankcatenumber,bank.bank_cate.name bankbankcatename,bizdate,nckd_depositbalance,amount,freezebalance,datasource";
        DataSet beiBankbalanceDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "bei_bankbalance", beiBankbalanceSelectField, beiBankbalanceFilter.toArray(), null);

        //日志打印
        StringBuffer beiBankbalanceGroupDataSetlog = new StringBuffer();
        DataSet beiBankbalanceGroupDataSetcopy = beiBankbalanceDataSet.copy();
        while (beiBankbalanceGroupDataSetcopy.hasNext()) {
            Row next = beiBankbalanceGroupDataSetcopy.next();
            beiBankbalanceGroupDataSetlog.append(next.getString("bankaccountnumber")).append(" # ");
        }
        log.info("资金总额按银行大类余额查询列表 " + beiBankbalanceGroupDataSetlog);

        DataSet parentAmount =  getParentBankAccountNumberAmount(beiBankbalanceDataSet.copy());
        List<String> depositbalanceList = new ArrayList<>();
        DataSet parentAmountCopy = parentAmount.copy();
        while (parentAmountCopy.hasNext()){
            Row next = parentAmountCopy.next();
            depositbalanceList.add(next.getString("parentcompanyaccount"));
        }
        log.info("银行母账户对应的上存余额汇总" + JSON.toJSONString(depositbalanceList));

        //排除母账户，母账户的资金总额=母账户的当前余额-所有子账户的上存余额
        DataSet dataSet1 = beiBankbalanceDataSet.filter("bankaccountnumber in numbers", Collections.singletonMap("numbers", depositbalanceList));
        DataSet dataSet2 = beiBankbalanceDataSet.filter("bankaccountnumber not in numbers", Collections.singletonMap("numbers", depositbalanceList));
        dataSet1 = dataSet1.join(parentAmount).on("bankaccountnumber", "parentcompanyaccount").select(beiBankbalanceDataSet.getRowMeta().getFieldNames(),new String[]{"nckd_depositbalance depositbalance_sum"}).finish();
        dataSet1 = dataSet1.updateField("amount","amount - depositbalance_sum");
        dataSet1 = dataSet1.removeFields("depositbalance_sum");
        DataSet union1 = dataSet1.union(dataSet2);

        //获取符合条件的虚拟账户列表
        QFilter acctstatusfilter = new QFilter("acctstatus", QCP.not_equals, "closed")
                .and(new QFilter("bank.finorgtype.id", QCP.not_equals, queryOne.getLong("id")))
                .and("opendate", QCP.less_equals, enddate);
        String getAcctSelectedFieds = "id,company,openorg,issetbankinterface,bank,bank.bank_cate.id bankbankcateid,bank.bank_cate.number bankbankcatenumber,bank.bank_cate.name bankbankcatename,bankaccountnumber,isvirtual,name,currencyname,defaultcurrency,opendate,acctstatus,acctstyle,accttype,acctproperty,manager,acctname,finorgtype";
        DataSet acctDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "bd_accountbanks", getAcctSelectedFieds, acctstatusfilter.toArray(), null);
        List<String> isvirtualAccountNoList = new ArrayList<>();
        //.and("isvirtual", QCP.equals, true)
        DataSet acctDataSetisvirtual = acctDataSet.copy().filter("isvirtual = true");
        while (acctDataSetisvirtual.hasNext()) {
            Row next = acctDataSetisvirtual.next();
            String bankaccountnumber = next.getString("bankaccountnumber");
            isvirtualAccountNoList.add(bankaccountnumber);
        }
        //受限资金管理
        String amRestrictedfundsmanagerSelectField = "id,org.id companyid,org.number companynumber,org.name companyname,bankacct.id accountbankid,bankacct.bankaccountnumber bankaccountnumber,unrestrictedamt";
        //增加受限(资金总额按银行大类采用虚体账户)
        QFilter businesstype = new QFilter("businesstype", QCP.equals, "1").and("billstatus", QCP.equals, "C")
                .and("bankacct.bankaccountnumber", QCP.in, isvirtualAccountNoList).and("restricteddate", QCP.less_equals, enddate);
        DataSet amRestrictedfundsmanagerDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "am_restrictedfundsmanager", amRestrictedfundsmanagerSelectField, businesstype.toArray(), null);
        amRestrictedfundsmanagerDataSet = amRestrictedfundsmanagerDataSet.groupBy(new String[]{"companyid", "bankaccountnumber"}).sum("unrestrictedamt").finish();

        //定期存款处理
        String cimDepositSelectField = "id,org.id companyid,org.number companynumber,org.name companyname,settleaccount.id accountbankid,settleaccount.bankaccountnumber bankaccountnumber,surplusamount";
        //定期存款处理(资金总额按银行大类采用虚体账户)
        QFilter cimDepositQfilter = new QFilter("billstatus", QCP.equals, "C")
                .and("finaccount", QCP.in, isvirtualAccountNoList).and("intdate", QCP.less_equals, enddate);
        DataSet cimDepositDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "cim_deposit", cimDepositSelectField, cimDepositQfilter.toArray(), null);
        cimDepositDataSet = cimDepositDataSet.groupBy(new String[]{"companyid", "bankaccountnumber"}).sum("surplusamount").finish();

        //最后 汇总 成资金总额按银行大类 余额查询的全部当前余额 + 受限资金管理的全部虚拟户当前可解除受限金额  + 虚拟户定期存款处理的剩余金额
        /*DataSet amountSum = beiBankbalanceDataSet.copy().groupBy().sum("amount").sum("freezebalance").finish();
        DataSet unrestrictedamtSum = amRestrictedfundsmanagerDataSet.groupBy().sum("unrestrictedamt").finish();
        DataSet surplusamountSum = cimDepositDataSet.groupBy().sum("surplusamount").finish();*/
        DataSet finish = acctDataSet.leftJoin(union1).on("bankaccountnumber", "bankaccountnumber")
                .select(new String[]{"bankaccountnumber", "bankbankcatename"}, new String[]{"amount","nckd_depositbalance"}).finish()
                .leftJoin(amRestrictedfundsmanagerDataSet).on("bankaccountnumber", "bankaccountnumber")
                .select(new String[]{"bankaccountnumber", "bankbankcatename", "amount","nckd_depositbalance"}, new String[]{"unrestrictedamt"}).finish()
                .leftJoin(cimDepositDataSet).on("bankaccountnumber", "bankaccountnumber")
                .select(new String[]{"bankaccountnumber", "bankbankcatename", "amount", "nckd_depositbalance", "unrestrictedamt"}, new String[]{"surplusamount"}).finish();
        finish = finish.updateField("amount", "case when amount is null then 0 else amount end");
        finish = finish.updateField("nckd_depositbalance", "case when nckd_depositbalance is null then 0 else nckd_depositbalance end");
        finish = finish.updateField("unrestrictedamt", "case when unrestrictedamt is null then 0 else unrestrictedamt end");
        finish = finish.updateField("surplusamount", "case when surplusamount is null then 0 else surplusamount end");

        finish = finish.addField("amount + nckd_depositbalance + unrestrictedamt + surplusamount", "totalfunds");

//        DynamicObject test = BusinessDataServiceHelper.newDynamicObject("nckd_testdocuments");
//        test.set("billno","test-A-" + new SimpleDateFormat("yyyyMMddHHmm").format(new Date()));
//        test.set("billstatus","A");
//        DynamicObjectCollection entryentity = test.getDynamicObjectCollection("entryentity");
//        //打印单据
//        DataSet recCopy = finish.copy();
//        while (recCopy.hasNext()) {
//            DynamicObject entry = entryentity.addNew();
//            Row row = recCopy.next();
//            entry.set("nckd_name", row.getString("bankbankcatename"));
//            entry.set("nckd_number", row.getString("bankaccountnumber"));
//            entry.set("nckd_amount", row.get("totalfunds"));
//            entry.set("nckd_text",null);
//        }
//        SaveServiceHelper.save(new DynamicObject[]{test});

        finish = finish.filter("totalfunds > 0");

        QingData data = null;
        if (startRow < 200) {
            data = new QingData();
            Map<String, Integer> dataindex = new HashMap<String, Integer>();
            dataindex.put("bankaccountnumber", 0);
            dataindex.put("bankbankcatename", 1);
            dataindex.put("amount", 2);
            dataindex.put("unrestrictedamt", 3);
            dataindex.put("surplusamount", 4);
            dataindex.put("nckd_depositbalance", 5);
            data.setDataindex(dataindex);

            List<Object[]> rows = new ArrayList<Object[]>();
            while (finish.hasNext()) {
                Row row = finish.next();
                Object[] obj = new Object[6];
                obj[0] = row.getString("bankaccountnumber");
                obj[1] = row.getString("bankbankcatename");
                obj[2] = row.getBigDecimal("amount");
                obj[3] = row.getBigDecimal("unrestrictedamt");
                obj[4] = row.getBigDecimal("surplusamount");
                obj[5] = row.getBigDecimal("nckd_depositbalance");
                rows.add(obj);
            }
            data.setRows(rows);
        }
        return data;
    }

    /**
     * 获取母账户下子账户所有的上存余额
     * @param beiBankbalanceDataSetCopy
     * @return
     */
    private DataSet getParentBankAccountNumberAmount(DataSet beiBankbalanceDataSetCopy) {
        //母子账户组 fca_acctgroup
        String fcaAcctgroupSelectField = "id,company.id companyid,company.number companynumber,company.name companyname,accountbank.id accountbankid,accountbank.bankaccountnumber parentcompanyaccount, " +
                "entrys.bankacct.id bankacctid,entrys.bankacct.bankaccountnumber subsidiarybankaccount,entrys.bankacct.company.id bankacctcompanyid,entrys.bankacct.company.number bankacctcompanynumber,entrys.bankacct.company.name bankacctcompanyname";
        QFilter fcaacctgroupFilter = new QFilter("enable", QCP.equals, "1");
        //有效的母子账户组
        DataSet fcaAcctgroupDataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), "fca_acctgroup", fcaAcctgroupSelectField, fcaacctgroupFilter.toArray(), null);

        DataSet finish = fcaAcctgroupDataSet.join(beiBankbalanceDataSetCopy).on("subsidiarybankaccount", "bankaccountnumber")
                .select(new String[]{"parentcompanyaccount"}, new String[]{"nckd_depositbalance"})
                .finish().groupBy(new String[]{"parentcompanyaccount"}).sum("nckd_depositbalance").finish();

        return finish;
    }


    @Override
    public void setFilterParameter(String filterParameter) {
        IPageCache pageCache = getPageCache();
        pageCache.put("qFilter", filterParameter);

    }

    @Override
    public String getFilterParameter() {
        return getPageCache().get("qFilter");
    }

    /**
     * 获取动态表单联查信息
     *
     * @param pageId
     * @param ctrKey
     * @return
     */
    @Override
    public List<QingLinkageInfo> getLinkageInfo(String pageId, String ctrKey) {
        //return IQingDataProvider.super.getLinkageInfo(pageId, ctrKey);
        List<QingLinkageInfo> infos = new ArrayList<QingLinkageInfo>();
        QingLinkageInfo info = new QingLinkageInfo();
        Map<String, String> formKey = new HashMap<>();
        AppInfo appInfo = AppMetadataCache.getAppInfo("bei");
        //String appId = this.getView().getFormShowParameter().getAppId();
        formKey.put("AppId", appInfo.getAppId()); //需要打开的表单所在应用的id
        //String formId = this.getView().getFormShowParameter().getFormId();
        formKey.put("FormId", "nckd_totalfundbybankrpt"); //需要打开的表单的id
        formKey.put("System", "IERP");
        formKey.put("CtrKey", ctrKey);
        info.setFormKey(JsonUtil.encodeToString(formKey));
        info.setFormDisplayName("资金总额报表按银行大类分布");//联查到表单的显示名称
        info.setFormPrimaryKey("bankbankcatename");//联查到表单的主键
        infos.add(info);//可以添加多个QingLinkageInfo对象
        this.getView().getPageCache().put("qingViewControlKey", ctrKey);//必要语句!
        return infos;
    }

    /**
     * <p>调用此接口，触发业务逻辑，具体业务联查实现此接口<p/>
     *
     * @param ids    轻分析得到动态表单需要联査的1d的集合
     * @param pageId
     * @param formId
     * @param appId
     */
    @Override
    public void fireLinkageInfo(List<String> ids, String pageId, String formId, String appId) {
        //IQingDataProvider.super.fireLinkageInfo(ids, pageId, formId, appId);
        /*具体的表单打开逻辑，业务自己去实现
        ids:联查到的主键的值
        pageId:触发联査的页面的pageId，可用于找到触发联査的页面: FormView view = (FormView)Sessiomanager.getCurrent().getView(pageId)
        formId:联查到的表单的id
        appId:联查到的表单所在应用的Id
        */

        /*注意: 如果需要使用芒穹的view.showForm 方式打开表单，需要添加以下代码*/
        // 组装 FormShomParaneter(披照业务场景亲实现)
        ReportShowParameter reportShowParameter = new ReportShowParameter();
        reportShowParameter.getOpenStyle().setShowType(ShowType.Modal);
        reportShowParameter.setAppId(appId);
        reportShowParameter.setFormId(formId);//报表标识
        //拿过滤条件，进行取数
        String qFilter = getPageCache().get("qFilter"); //从仪表板进去 拿不到
        //通过此方法拿到过滤参数
        Map<String, Object> filterParam = new HashMap<>();
        if (qFilter != null) {
            //通过此方法拿到过滤参数
            filterParam = (Map) JSON.parseObject(qFilter, Map.class);
        }
        // 设置报表过滤条件
        ReportQueryParam reportQueryParam = new ReportQueryParam();
        //FilterInfo filterInfo = new FilterInfo();
        filterParam.put("nckd_orgview", filterParam.get("nckd_orgview"));
        filterParam.put("nckd_org", filterParam.get("nckd_org"));
        filterParam.put("nckd_currency", filterParam.get("nckd_currency"));
        filterParam.put("nckd_querydate", filterParam.get("nckd_querydate"));
        filterParam.put("nckd_amountunit", filterParam.get("nckd_amountunit"));
        filterParam.put("bankbankcatename", ids);
        //reportQueryParam.setFilter(filterInfo);
        reportQueryParam.setCustomParam(filterParam);
        reportShowParameter.setQueryParam(reportQueryParam);

        /*******************************showForm必要的代码******************************************/
        IFormView view = SessionManager.getCurrent().getView(pageId);
        String ctrKey = this.getView().getPageCache().get("qingViewControlKey");
        if (ctrKey != null) {
            if (view.getControl(ctrKey) instanceof IQingAnalysis) {
                //设计器的场景，直接showForm
                view.showForm(reportShowParameter);
                return;
            }
        }
        //其他场景需要，返回FormShowParameter，由轻分析来 showForm
        this.getView().setClientReturnData(ListShowParameter.toJsonString(reportShowParameter));
        /*******************************showForm必要的代码******************************************/
    }
}
